package com.minube.flights.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.minube.flights.data.FlightBoard;
import com.minube.flights.data.FlightEntry;
import com.minube.flights.util.FlightException;

public class FlightReader extends AbstractFlightReader {

	private final String QUERY_BASE_URL             = "http://api.minube.com/search/flights.xml?api_key=41e59fa5e732afe9dc70ff1c06666314";
	private final String QUERY_SOURCE_IATA_URL      = "&source_iata=";
	private final String QUERY_DESTINATION_IATA_URL = "&destiny_iata=";
	private final String QUERY_DEPARTURE_DATE_URL   = "&depart_date=";
	private final String QUERY_RETURN_DATE_URL      = "&return_date=";
	private final String QUERY_DIRECT_FLIGHT        = "&stops=direct";
	
	private final String FLIGHT_BASE_URL = "http://api.minube.com/search/fetch.xml?api_key=41e59fa5e732afe9dc70ff1c06666314";
	private final String FLIGHT_ID_URL   = "&sid=";
	private final String FLIGHT_TYPE_URL = "&type=flights";
	
	private String flightId;

	public FlightReader(String sourceIATA, String destinationIATA,
			Date departureDate, Date returnDate) {

		super(sourceIATA, destinationIATA, departureDate, returnDate);
	}
	
	public void launchQuery() throws FlightException {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			
			String queryString = QUERY_BASE_URL + 
								 QUERY_SOURCE_IATA_URL + sourceAirport +
								 QUERY_DESTINATION_IATA_URL + destinationAirport +
								 QUERY_DEPARTURE_DATE_URL + sdf.format(departureDate) + 
								 QUERY_RETURN_DATE_URL + sdf.format(returnDate) + 
								 QUERY_DIRECT_FLIGHT;
			
			URL queryURL = new URL(queryString);
			
			String queryData = readUrl(queryURL);
			
			Pattern p = Pattern.compile("<id>(.*?)</id>");
			Matcher m = p.matcher(queryData);
			
			if (m.find())
				flightId = m.group(1);

		} catch (Exception e) {
			throw new FlightException(e.getMessage(), e.getCause());
		}
	}

	public void process() throws FlightException {
		try {
			String flightString = FLIGHT_BASE_URL +
		 			  FLIGHT_TYPE_URL + 
		 			  FLIGHT_ID_URL + flightId;
			
			URL flightURL = new URL (flightString);
			
			Pattern p;
			Matcher m;
			
			while(true) {
				String flightData = readUrl(flightURL);
				
				p = Pattern.compile("<search_status>(.*?)</search_status>");
				m = p.matcher(flightData);
				
				m.find();
				
				if (m.group(1).equals("complete")) {
					fb = new FlightBoard();
					
					p = Pattern.compile("<flight>(.*?)</flight>");
					m = p.matcher(flightData);
					
					for ( ; m.find(); )
						processBoard(m.group(1));
					
					break;
				}
			}
		} catch (Exception e) {
			throw new FlightException(e.getMessage(), e.getCause());
		}
	}

	private void processBoard(String flight) throws FlightException {
		try {
			Pattern p;
			Matcher m;
			
			String company = null;
			String departureArrivalDate = null;
			String departureArrivalTime = null;
			String departureTime = null;
			String price = null;
			String returnArrivalDate = null;
			String returnArrivalTime = null;
			String returnTime = null;
			String type = null;
			
			// Company name
			p = Pattern.compile("<airline><\\!\\[CDATA\\[(.*?)\\]\\]></airline>");
			m = p.matcher(flight);

			if (m.find())
				company = m.group(1);
			
			// Departure and return arrival dates
			p = Pattern.compile("<arrivaldate>(.*?)</arrivaldate>");
			m = p.matcher(flight);
			
			if (m.find())
				departureArrivalDate = m.group(1);
			
			if (m.find())
				returnArrivalDate = m.group(1);
			
			// Departure and return arrival times
			p = Pattern.compile("<arrivaltime>(.*?)</arrivaltime>");
			m = p.matcher(flight);
			
			if (m.find())
				departureArrivalTime = m.group(1);
			
			if (m.find())
				returnArrivalTime = m.group(1);
			
			// Departure and return times
			p = Pattern.compile("<time>(.*?)</time>");
			m = p.matcher(flight);
			
			if (m.find())
				departureTime = m.group(1);
			
			if (m.find())
				returnTime = m.group(1);
			
			// Price
			p = Pattern.compile("<price>(.*?)</price>");
			m = p.matcher(flight);
			
			if (m.find())
				price = m.group(1);
			
			// Type
			p = Pattern.compile("<type>(.*?)</type>");
			m = p.matcher(flight);
			
			if (m.find())
				type = m.group(1);

			// Load entry
			FlightEntry entry = new FlightEntry();

			entry.setCompany(company);
			entry.setDepartureArrivalDate(departureArrivalDate);
			entry.setDepartureArrivalTime(departureArrivalTime);
			entry.setDepartureTime(departureTime);
			entry.setPrice(price);
			entry.setReturnArrivalDate(returnArrivalDate);
			entry.setReturnArrivalTime(returnArrivalTime);
			entry.setReturnTime(returnTime);
			entry.setType(type);

			fb.addFlightEntry(entry);
		} catch (Exception e) {
			throw new FlightException(e.getMessage(), e.getCause());
		}
	}

	private static String readUrl(URL url) throws MalformedURLException,
			IOException {
		StringBuffer sb = new StringBuffer();

		HttpURLConnection conn = (HttpURLConnection) url.openConnection();

		conn.setRequestMethod("GET");

		BufferedReader br = new BufferedReader(new InputStreamReader(
				conn.getInputStream()));

		String line = null;

		while ((line = br.readLine()) != null)
			sb.append(line);
		
		System.out.println(sb.toString());
		System.out.println("--------------------");

		String ret = sb.toString();
		
		return ret.replaceAll("[\r\n]", "");
	}
}
